package com.ruoyi.workflow.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.workflow.constant.VariablesConstants;
import com.ruoyi.workflow.enums.FlowInstanceStateEnum;
import com.ruoyi.workflow.enums.FlowModelStateEnum;
import com.ruoyi.workflow.enums.SuspensionStateEnum;
import com.ruoyi.workflow.exception.FlowInstanceException;
import com.ruoyi.workflow.mapper.FlowInstanceMapper;
import com.ruoyi.workflow.pojo.entity.FlowInstance;
import com.ruoyi.workflow.pojo.entity.FlowModel;
import com.ruoyi.workflow.pojo.entity.PearlFlowRecord;
import com.ruoyi.workflow.pojo.param.MyStartInstanceParams;
import com.ruoyi.workflow.pojo.param.RevokeInstanceParams;
import com.ruoyi.workflow.pojo.param.StartInstanceParams;
import com.ruoyi.workflow.pojo.vo.ActivityCompleteStatusVO;
import com.ruoyi.workflow.pojo.vo.MyStartInstanceVO;
import com.ruoyi.workflow.service.IFlowInstanceService;
import com.ruoyi.workflow.service.IFlowModelService;
import com.ruoyi.workflow.service.IPearlFlowRecordService;
import org.apache.commons.io.IOUtils;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 自定义流程实例Service业务层处理
 *
 * @author ruoyi
 * @date 2023-12-19
 */
@Service
public class FlowInstanceServiceImpl implements IFlowInstanceService {

    @Autowired
    private FlowInstanceMapper flowInstanceMapper;

    @Autowired
    private IFlowModelService flowModelService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    @Override
    @Transactional
    public String start(StartInstanceParams params) {
        // 1. 查询模型并校验
        Long modelId = params.getModelId();
        if (ObjectUtil.isNull(modelId)) {
            throw new ServiceException("模型ID不能为空");
        }
        FlowModel flowModel = flowModelService.selectFlowModelById(modelId);
        if (ObjectUtil.isNull(flowModel)) {
            throw new ServiceException("模型不存在");
        }
        Integer modelState = flowModel.getModelState();
        if (!FlowModelStateEnum.PUBLISHED.getCode().equals(modelState)) {
            throw new ServiceException("模型未发布");
        }
        Integer suspensionState = flowModel.getSuspensionState();
        if (SuspensionStateEnum.SUSPENSION.getCode().equals(suspensionState)) {
            throw new ServiceException("当前模型已挂起");
        }
        if (ObjectUtil.isNull(params.getTitle())) { // 主题
            params.setTitle(SecurityUtils.getUsername() + "发起的" + flowModel.getName());
        }
        // 2. 设置变量
        Map<String, Object> variables = params.getVariables(); // 请求中的
        variables.put(VariablesConstants.INITIATOR, SecurityUtils.getUserId()); // 设置额外的，便于后期处理获取
        variables.put(VariablesConstants.MODEL_ID, modelId);
        variables.put(VariablesConstants.FORM_ID, flowModel.getFormId());
        variables.put(VariablesConstants.TITLE, params.getTitle());

        // 3. 启动流程
        String defId = flowModel.getDefId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceById(defId)
                .businessKey(params.getBusinessKey())
                .setVariables(variables)
                .execute();
        // 4. 流程实例扩展表
/*        FlowInstance flowInstance = new FlowInstance();
        flowInstance.setInstanceId(processInstance.getProcessInstanceId());
        flowInstance.setFormId(flowModel.getFormId());
        flowInstance.setCreateTime(new Date());
        flowInstance.setInitiator(SecurityUtils.getUserId());
        flowInstance.setModelId(modelId);
        flowInstance.setBusinessKey(params.getBusinessKey());
        if (ObjectUtil.isNull(params.getTitle())) {
            flowInstance.setTitle(SecurityUtils.getUsername() + "发起的" + flowModel.getName());
        }
        flowInstance.setState(FlowInstanceStateEnum.PROCESSING.getCode());
        flowInstanceMapper.insertFlowInstance(flowInstance);*/

        return processInstance.getProcessInstanceId();
    }

    /**
     * 查询自定义流程实例
     *
     * @param id 自定义流程实例主键
     * @return 自定义流程实例
     */
    @Override
    public FlowInstance selectFlowInstanceById(Long id) {
        return flowInstanceMapper.selectFlowInstanceById(id);
    }

    @Override
    public FlowInstance selectFlowByInstanceId(String insId) {
        return flowInstanceMapper.selectByInstanceId(insId);
    }

    /**
     * 查询自定义流程实例列表
     *
     * @param pearlFlowInstance 自定义流程实例
     * @return 自定义流程实例
     */
    @Override
    public List<FlowInstance> selectFlowInstanceList(FlowInstance pearlFlowInstance) {
        return flowInstanceMapper.selectFlowInstanceList(pearlFlowInstance);
    }

    /**
     * 新增自定义流程实例
     *
     * @param pearlFlowInstance 自定义流程实例
     * @return 结果
     */
    @Override
    public int insertFlowInstance(FlowInstance pearlFlowInstance) {
        pearlFlowInstance.setCreateTime(DateUtils.getNowDate());
        return flowInstanceMapper.insertFlowInstance(pearlFlowInstance);
    }

    /**
     * 修改自定义流程实例
     *
     * @param pearlFlowInstance 自定义流程实例
     * @return 结果
     */
    @Override
    public int updateFlowInstance(FlowInstance pearlFlowInstance) {
        pearlFlowInstance.setUpdateTime(DateUtils.getNowDate());
        return flowInstanceMapper.updateFlowInstance(pearlFlowInstance);
    }

    /**
     * 批量删除自定义流程实例
     *
     * @param ids 需要删除的自定义流程实例主键
     * @return 结果
     */
    @Override
    public int deleteFlowInstanceByIds(Long[] ids) {
        return flowInstanceMapper.deleteFlowInstanceByIds(ids);
    }

    /**
     * 删除自定义流程实例信息
     *
     * @param id 自定义流程实例主键
     * @return 结果
     */
    @Override
    public int deleteFlowInstanceById(Long id) {
        return flowInstanceMapper.deleteFlowInstanceById(id);
    }

    @Override
    public AjaxResult transferRecords(String processInstanceId) {
        // 方案1：查询历史活动节点，循环查任务、审批人信息、意见，绑定了原生的，扩展有限
        // 方案2：自定义审批记录表，然后查询，对于各种动作可以很好的处理。
        return null;
    }

    @Override
    @Transactional
    public void revoke(RevokeInstanceParams params) {
        // 1. 查询流程实例
        FlowInstance flowInstance = flowInstanceMapper.selectFlowInstanceById(params.getId());
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(flowInstance.getInstanceId())
                .singleResult();
        if (ObjectUtil.isNull(processInstance)) {
            throw new FlowInstanceException("当前流程实例不存在");
        }

        // 2. 未被任何人处理的流程才允许撤回
        // 查询是否有已完成的任务
        List<HistoricActivityInstance> historyList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(flowInstance.getInstanceId())
                .activityType("userTask")
                .finished()
                .list();
        if (CollUtil.isNotEmpty(historyList)) {
            throw new FlowInstanceException("当前流程实例已流转，不允许撤回");
        }

        // 3. 删除流程
        runtimeService.deleteProcessInstance(flowInstance.getInstanceId(), "revoke");

        // 4. 更新自定义流程实例表
        flowInstance.setState(FlowInstanceStateEnum.REVOKED.getCode());
        flowInstance.setUpdateTime(new Date());
        flowInstance.setUpdateBy(SecurityUtils.getUsername());
        flowInstanceMapper.updateFlowInstance(flowInstance);

        // 5. 新增流转记录
        PearlFlowRecord record = new PearlFlowRecord();
        record.setInsId(flowInstance.getId());
        record.setHandlerUserName(SecurityUtils.getUsername());
        record.setHandlerAction("撤回");
        IPearlFlowRecordService flowRecordService = SpringUtil.getBean(IPearlFlowRecordService.class);
        flowRecordService.insertPearlFlowRecord(record);
    }

    @Override
    public List<MyStartInstanceVO> selectMyFlowInstanceList(MyStartInstanceParams params) {
        params.setInitiator(SecurityUtils.getUserId());
        return flowInstanceMapper.selectMyFlowInstanceList(params);
    }

    @Override
    public Map<String, Object> getFormVarsByInsId(Long id) {
        Map<String, Object> result = new HashMap<>();
        FlowInstance flowInstance = flowInstanceMapper.selectFlowInstanceById(id); // 扩展表
        Integer state = flowInstance.getState();
        // 审批中 || 挂起 状态 查询运行时变量
        if (FlowInstanceStateEnum.PROCESSING.getCode().equals(state)
                || FlowInstanceStateEnum.SUSPENSION.getCode().equals(state)) {
            Object variable = runtimeService.getVariables(flowInstance.getInstanceId()).get(VariablesConstants.FORM_VARS);
            result.put(VariablesConstants.FORM_VARS, variable);
        } else {
            // 其他状态都是已结束，查询历史变量
            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(flowInstance.getInstanceId())
                    .variableName(VariablesConstants.FORM_VARS)
                    .singleResult();
            Object value = historicVariableInstance.getValue();
            result.put(VariablesConstants.FORM_VARS, value);
        }
        return result;
    }


    @Override
    public Map<String, Object> getDynamicModelPic(Long id) throws IOException {
        // 查询扩展表
        FlowInstance flowInstance = flowInstanceMapper.selectFlowInstanceById(id);
        List<ActivityCompleteStatusVO> activityCompleteStatusVOList = new ArrayList<>();
        /*        Task task = taskService.createTaskQuery().taskId(id).singleResult();   // 查询任务信息*/

        // 查询已完成的历史节点
        List<HistoricActivityInstance> finishedList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(flowInstance.getInstanceId())
                .finished()
                .list();
        for (HistoricActivityInstance activityInstance : finishedList) {
            ActivityCompleteStatusVO vo = new ActivityCompleteStatusVO();
            vo.setKey(activityInstance.getActivityId());
            vo.setCompleted(true);
            activityCompleteStatusVOList.add(vo);
        }

        // 未完成节点
        List<HistoricActivityInstance> unfinishedList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(flowInstance.getInstanceId())
                .unfinished()
                .list();
        for (HistoricActivityInstance activityInstance : unfinishedList) {
            ActivityCompleteStatusVO vo = new ActivityCompleteStatusVO();
            vo.setKey(activityInstance.getActivityId());
            vo.setCompleted(false);
            activityCompleteStatusVOList.add(vo);
        }

        // 查询流程图
        FlowModel flowModel = flowModelService.selectFlowModelById(flowInstance.getModelId());// 模型扩展表
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(flowModel.getDefId()).singleResult();
        InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
        String xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("nodeData", activityCompleteStatusVOList);
        result.put("xmlData", xmlData);
        return result;
    }
}
